home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Python 1.4 / Python 1.4 source / Mac / scripts / mkapplet.py < prev    next >
Encoding:
Python Source  |  1996-09-16  |  6.9 KB  |  300 lines  |  [TEXT/Pyth]

  1. """Create an applet from a Python script.
  2.  
  3. This puts up a dialog asking for a Python source file ('TEXT').
  4. The output is a file with the same name but its ".py" suffix dropped.
  5. It is created by copying an applet template and then adding a 'PYC '
  6. resource named __main__ containing the compiled, marshalled script.
  7. """
  8.  
  9. DEBUG=0
  10.  
  11. import sys
  12. sys.stdout = sys.stderr
  13.  
  14. import string
  15. import os
  16. import marshal
  17. import imp
  18. import macfs
  19. import MACFS
  20. import MacOS
  21. from Res import *
  22. import macostools
  23.  
  24. # .pyc file (and 'PYC ' resource magic number)
  25. MAGIC = imp.get_magic()
  26.  
  27. # Template file (searched on sys.path)
  28. TEMPLATE = "PythonApplet"
  29.  
  30. # Specification of our resource
  31. RESTYPE = 'PYC '
  32. RESNAME = '__main__'
  33.  
  34. # A resource with this name sets the "owner" (creator) of the destination
  35. # XXXX Should look for id=0
  36. OWNERNAME = "owner resource"
  37.  
  38. # OpenResFile mode parameters
  39. READ = 1
  40. WRITE = 2
  41.  
  42. def findtemplate():
  43.     """Locate the applet template along sys.path"""
  44.     for p in sys.path:
  45.         template = os.path.join(p, TEMPLATE)
  46.         try:
  47.             template, d1, d2 = macfs.ResolveAliasFile(template)
  48.             break
  49.         except (macfs.error, ValueError):
  50.             continue
  51.     else:
  52.         die("Template %s not found on sys.path" % `TEMPLATE`)
  53.         return
  54.     template = template.as_pathname()
  55.     return template
  56.  
  57. def main():
  58.     
  59.     # Find the template
  60.     # (there's no point in proceeding if we can't find it)
  61.     
  62.     template = findtemplate()
  63.     if DEBUG:
  64.         print 'Using template', template
  65.             
  66.     # Ask for source text if not specified in sys.argv[1:]
  67.     
  68.     if not sys.argv[1:]:
  69.         srcfss, ok = macfs.PromptGetFile('Select Python source file:', 'TEXT')
  70.         if not ok:
  71.             return
  72.         filename = srcfss.as_pathname()
  73.         tp, tf = os.path.split(filename)
  74.         if tf[-3:] == '.py':
  75.             tf = tf[:-3]
  76.         else:
  77.             tf = tf + '.applet'
  78.         dstfss, ok = macfs.StandardPutFile('Save application as:', tf)
  79.         if not ok: return
  80.         process(template, filename, dstfss.as_pathname())
  81.     else:
  82.         
  83.         # Loop over all files to be processed
  84.         for filename in sys.argv[1:]:
  85.             process(template, filename, '')
  86.  
  87. def process(template, filename, output):
  88.     
  89.     if DEBUG:
  90.         print "Processing", `filename`, "..."
  91.     
  92.     # Read the source and compile it
  93.     # (there's no point overwriting the destination if it has a syntax error)
  94.     
  95.     fp = open(filename)
  96.     text = fp.read()
  97.     fp.close()
  98.     try:
  99.         code = compile(text, filename, "exec")
  100.     except (SyntaxError, EOFError):
  101.         die("Syntax error in script %s" % `filename`)
  102.         return
  103.     
  104.     # Set the destination file name
  105.     
  106.     if string.lower(filename[-3:]) == ".py":
  107.         destname = filename[:-3]
  108.         rsrcname = destname + '.rsrc'
  109.     else:
  110.         destname = filename + ".applet"
  111.         rsrcname = filename + '.rsrc'
  112.     
  113.     if output:
  114.         destname = output
  115.         
  116.     # Try removing the output file
  117.     try:
  118.         os.unlink(output)
  119.     except os.error:
  120.         pass
  121.         
  122.  
  123.     # Create FSSpecs for the various files
  124.         
  125.     template_fss = macfs.FSSpec(template)
  126.     template_fss, d1, d2 = macfs.ResolveAliasFile(template_fss)
  127.     dest_fss = macfs.FSSpec(destname)
  128.     
  129.     # Copy data (not resources, yet) from the template
  130.     
  131.     tmpl = open(template, "rb")
  132.     dest = open(destname, "wb")
  133.     data = tmpl.read()
  134.     if data:
  135.         dest.write(data)
  136.     dest.close()
  137.     tmpl.close()
  138.     
  139.     # Open the output resource fork
  140.     
  141.     try:
  142.         output = FSpOpenResFile(dest_fss, WRITE)
  143.     except MacOS.Error:
  144.         if DEBUG:
  145.             print "Creating resource fork..."
  146.         CreateResFile(destname)
  147.         output = FSpOpenResFile(dest_fss, WRITE)
  148.         
  149.     # Copy the resources from the target specific resource template, if any
  150.     typesfound, ownertype = [], None
  151.     try:
  152.         input = FSpOpenResFile(rsrcname, READ)
  153.     except (MacOS.Error, ValueError):
  154.         pass
  155.     else:
  156.         typesfound, ownertype = copyres(input, output, [], 0)
  157.         CloseResFile(input)
  158.         
  159.     # Check which resource-types we should not copy from the template
  160.     skiptypes = []
  161.     if 'SIZE' in typesfound: skiptypes.append('SIZE')
  162.     if 'BNDL' in typesfound: skiptypes = skiptypes + ['BNDL', 'FREF', 'icl4', 
  163.             'icl8', 'ics4', 'ics8', 'ICN#', 'ics#']
  164.     skipowner = (ownertype <> None)
  165.     
  166.     # Copy the resources from the template
  167.     
  168.     input = FSpOpenResFile(template_fss, READ)
  169.     dummy, tmplowner = copyres(input, output, skiptypes, skipowner)
  170.     if ownertype == None:
  171.         ownertype = tmplowner
  172.     CloseResFile(input)
  173.     if ownertype == None:
  174.         die("No owner resource found in either resource file or template")    
  175.     
  176.     # Now set the creator, type and bundle bit of the destination
  177.     dest_finfo = dest_fss.GetFInfo()
  178.     dest_finfo.Creator = ownertype
  179.     dest_finfo.Type = 'APPL'
  180.     dest_finfo.Flags = dest_finfo.Flags | MACFS.kHasBundle
  181.     dest_finfo.Flags = dest_finfo.Flags & ~MACFS.kHasBeenInited
  182.     dest_fss.SetFInfo(dest_finfo)
  183.     
  184.     # Make sure we're manipulating the output resource file now
  185.     
  186.     UseResFile(output)
  187.     
  188.     # Delete any existing 'PYC ' resource named __main__
  189.     
  190.     try:
  191.         res = Get1NamedResource(RESTYPE, RESNAME)
  192.         res.RemoveResource()
  193.     except Error:
  194.         pass
  195.     
  196.     # Create the raw data for the resource from the code object
  197.     
  198.     data = marshal.dumps(code)
  199.     del code
  200.     data = (MAGIC + '\0\0\0\0') + data
  201.     
  202.     # Create the resource and write it
  203.     
  204.     id = 0
  205.     while id < 128:
  206.         id = Unique1ID(RESTYPE)
  207.     res = Resource(data)
  208.     res.AddResource(RESTYPE, id, RESNAME)
  209.     res.WriteResource()
  210.     res.ReleaseResource()
  211.     
  212.     # Close the output file
  213.     
  214.     CloseResFile(output)
  215.     
  216.     macostools.touched(dest_fss)
  217.     if DEBUG:
  218.         print "Applet created:", destname
  219.  
  220.  
  221. # Copy resources between two resource file descriptors.
  222. # skip a resource named '__main__' or (if skipowner is set) 'Owner resource'.
  223. # Also skip resources with a type listed in skiptypes.
  224. #
  225. def copyres(input, output, skiptypes, skipowner):
  226.     ctor = None
  227.     alltypes = []
  228.     UseResFile(input)
  229.     ntypes = Count1Types()
  230.     for itype in range(1, 1+ntypes):
  231.         type = Get1IndType(itype)
  232.         if type in skiptypes:
  233.             continue
  234.         alltypes.append(type)
  235.         nresources = Count1Resources(type)
  236.         for ires in range(1, 1+nresources):
  237.             res = Get1IndResource(type, ires)
  238.             id, type, name = res.GetResInfo()
  239.             lcname = string.lower(name)
  240.             if (type, lcname) == (RESTYPE, RESNAME):
  241.                 continue # Don't copy __main__ from template
  242.             # XXXX should look for id=0
  243.             if lcname == OWNERNAME:
  244.                 if skipowner:
  245.                     continue # Skip this one
  246.                 else:
  247.                     ctor = type
  248.             size = res.size
  249.             attrs = res.GetResAttrs()
  250.             if DEBUG:
  251.                 print id, type, name, size, hex(attrs)
  252.             res.LoadResource()
  253.             res.DetachResource()
  254.             UseResFile(output)
  255.             try:
  256.                 res2 = Get1Resource(type, id)
  257.             except MacOS.Error:
  258.                 res2 = None
  259.             if res2:
  260.                 if DEBUG:
  261.                     print "Overwriting..."
  262.                 res2.RemoveResource()
  263.             res.AddResource(type, id, name)
  264.             res.WriteResource()
  265.             attrs = attrs | res.GetResAttrs()
  266.             if DEBUG:
  267.                 print "New attrs =", hex(attrs)
  268.             res.SetResAttrs(attrs)
  269.             UseResFile(input)
  270.     return alltypes, ctor
  271.  
  272.  
  273. # Show a message and exit
  274.  
  275. def die(str):
  276.     message(str)
  277.     sys.exit(1)
  278.  
  279.  
  280. # Show a message
  281.  
  282. def message(str, id = 256):
  283.     from Dlg import *
  284.     d = GetNewDialog(id, -1)
  285.     if not d:
  286.         print "Error:", `str`
  287.         print "DLOG id =", id, "not found."
  288.         return
  289.     tp, h, rect = d.GetDialogItem(2)
  290.     SetDialogItemText(h, str)
  291.     d.SetDialogDefaultItem(1)
  292.     while 1:
  293.         n = ModalDialog(None)
  294.         if n == 1: break
  295.     del d
  296.  
  297.  
  298. if __name__ == '__main__':
  299.     main()
  300.